/*
 * Copyright 2003 Program of Computer Graphics, Cornell University
 *     580 Rhodes Hall
 *     Cornell University
 *     Ithaca NY 14853
 * Web: http://www.graphics.cornell.edu/
 * 
 * Not for commercial use. Do not redistribute without permission.
 */
#include "stdafx.h"

#include "Geometry.h"
#include "Triangle.h"

GeometrySet::GeometrySet()
{
}

GeometrySet::GeometrySet(const GeometrySet &copy, bool copyContents)
:tris(copy.tris,copyContents),others(copy.others,copyContents)
{
}

GeometrySet::~GeometrySet()
{
}

void GeometrySet::expandBoxToInclude(AxisAlignedBox *box) const
{
  int size = tris.size();
  for(int i=0;i<size;i++) {
    tris[i]->expandBoxToInclude(box);
  }
  size = others.size();
  for(int j=0;j<size;j++) {
    others[j]->expandBoxToInclude(box);
  }
}

void GeometrySet::setSubsetIntersectsBox(const GeometrySet &set, const AxisAlignedBox &box)
{
  //expand box slightly before testing for intersection to reduce chance of rounding errors
  //causing incorrect results
  AxisAlignedBox buildBox(box);
  buildBox.epsilonExpand(EPSM_BUILD);
  int size = set.tris.size();
  tris.removeAll();
  for(int i=0;i<size;i++) {
    const Triangle *t = set.tris[i];
    if (t->intersectsBox(buildBox))
      tris.append((Triangle*)t);
  }
  size = set.others.size();
  others.removeAll();
  for(int j=0;j<size;j++) {
    if (set.others[j]->intersectsBox(buildBox)) 
      others.append(set.others[j]);
  }
}

PrimitiveList *GeometrySet::compileToPrimitiveList(PoolAllocator *pool)
{
  PrimitiveList *retval = NULL;
  PrimitiveList *prevList = NULL;
  if (others.size() > 0) {
    int size = others.size();
    //we need to sort the others by type first before compiling each type individually
    int cur = 0;
    do {
      //first create a run of objects, all with the same type
      int type = others[cur]->getType();
      int limit = cur+1; //limit is index to first object with a different type
      while((limit<size)&&(others[limit]->getType()==type)) limit++;
      for(int i=limit+1;i<size;i++) {
        if (others[i]->getType()==type) {
          GeometryObject *temp = others[limit];
          others[limit] = others[i];
          others[i] = temp;
          limit++;
        }
      }
      //then compile the run of objects of a single type into a primitive list
      PrimitiveList *list = others[cur]->compile(limit-cur,(const GeometryObject**)&(others[cur]),pool);
      list->next = NULL;
      //and link this list to any previous lists
      if (prevList) {
        prevList->next = list;
        prevList = list;
      } else {
        retval = prevList = list;
      }
      cur = limit;
      //if there are still more objects, then repeat until all types have been handled
    } while (cur < size) ;
  }
  //because triangle lists are stored naked (without the usual PrimitiveList header), they
  //can only appear at the end of the of primitive lists (since they have no next field)
  if (tris.size() > 0) {
    PrimitiveList *list = tris[0]->compile(tris.size(),(const GeometryObject**)&(tris[0]),pool);
    if (prevList) {
      prevList->next = list;
      prevList = list;
    } else {
      retval = prevList = list;
    }
  }
  return retval;
}

void GeometrySet::estimateFixedSplits(KDFixedSplitEstimator &splits) const
{
  int size = tris.size();
  for(int i=0;i<size;i++) {
    AxisAlignedBox bounds = tris[i]->estimateIntersectionBounds(splits.boundsBig);
    splits.addTri(1,bounds);
  }
  size = others.size();
  for(int j=0;j<size;j++) {
    AxisAlignedBox bounds = others[j]->estimateIntersectionBounds(splits.boundsBig);
    splits.addOther(others[j]->estimateRelativeCost(),bounds);
  }
}

void GeometrySet::estimateAllSplits(KDAllSplitEstimator &splits) const
{
  int size = tris.size();
  for(int i=0;i<size;i++) {
    AxisAlignedBox bounds = tris[i]->estimateIntersectionBounds(splits.boundsBig);
    splits.addTri(1,bounds);
  }
  size = others.size();
  for(int j=0;j<size;j++) {
    AxisAlignedBox bounds = others[j]->estimateIntersectionBounds(splits.boundsBig);
    splits.addOther(others[j]->estimateRelativeCost(),bounds);
  }
}

